﻿using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Collections.Generic;
using System.Text;

namespace GLLog.Net
{
    /// <summary>
    /// 通讯协议
    /// </summary>
    public class Protocol
    {
        /// <summary>
        /// 通讯协议版本号
        /// </summary>
        public const string ver = "1.0.0";
        /// <summary>
        /// 通讯协议版本号长度
        /// </summary>
        public const byte ver_len = 5;
        /// <summary>
        /// 包长
        /// </summary>
        public const byte pack_len = 4;
        /// <summary>
        /// 客户端是否缓存0否，1是
        /// </summary>
        public const byte client_cache_len = 1;
        /// <summary>
        /// 客户端是否加密
        /// </summary>
        public const byte client_encrypt_len = 1;

        public byte[] MarkPack(byte[] info)
        {
            byte[] sendbyte = new byte[pack_len + ver_len + client_cache_len + client_encrypt_len + info.Length];
            byte[] _pack_len = new byte[pack_len];
            byte[] _ver = new byte[ver_len];
            byte[] _client_cache_len = BitConverter.GetBytes(true);
            byte[] _client_encrypt_len = BitConverter.GetBytes(Client.Start.Encryp);
            try
            {
                _ver = Encoding.Default.GetBytes(ver);
                _pack_len = BitConverter.GetBytes(info.Length);
                if (_client_encrypt_len[0] == 1)
                {
                    Comms.Comms c = new Comms.Comms();
                    info = c.EncryptEx(info, GLLog.Client.Start.EncrypCode);
                }
                Array.Copy(_pack_len, 0, sendbyte, 0, _pack_len.Length);
                Array.Copy(_ver, 0, sendbyte, _pack_len.Length, _ver.Length);
                Array.Copy(_client_cache_len, 0, sendbyte, _pack_len.Length + _ver.Length, _client_cache_len.Length);
                Array.Copy(_client_encrypt_len, 0, sendbyte, _pack_len.Length + _ver.Length + _client_cache_len.Length, _client_encrypt_len.Length);
                Array.Copy(info, 0, sendbyte, _pack_len.Length + _ver.Length + _client_cache_len.Length + _client_encrypt_len.Length, info.Length);
                return sendbyte;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public byte[] MarkPack(string MIP, string MLevel, string MLogger, string MLogMessage, string MException, DateTime MAddTime)
        {
            string sendtxt = MIP + "↓" + MLevel + "↓" + MLogger + "↓" + MLogMessage + "↓" + MException + "↓" + MAddTime;
            byte[] info = Encoding.Default.GetBytes(sendtxt);
            byte[] sendbyte = new byte[pack_len + ver_len + client_cache_len + client_encrypt_len + info.Length];
            byte[] _pack_len = new byte[pack_len];
            byte[] _ver = new byte[ver_len];
            byte[] _client_cache_len = BitConverter.GetBytes(false);
            byte[] _client_encrypt_len = BitConverter.GetBytes(Client.Start.Encryp);
            try
            {
                _ver = Encoding.Default.GetBytes(ver);
                _pack_len = BitConverter.GetBytes(info.Length);
                if (_client_encrypt_len[0] == 1)
                {
                    Comms.Comms c = new Comms.Comms();
                    info = c.EncryptEx(info, GLLog.Client.Start.EncrypCode);
                }
                Array.Copy(_pack_len, 0, sendbyte, 0, _pack_len.Length);
                Array.Copy(_ver, 0, sendbyte, _pack_len.Length, _ver.Length);
                Array.Copy(_client_cache_len, 0, sendbyte, _pack_len.Length + _ver.Length, _client_cache_len.Length);
                Array.Copy(_client_encrypt_len, 0, sendbyte, _pack_len.Length + _ver.Length + _client_cache_len.Length, _client_encrypt_len.Length);
                Array.Copy(info, 0, sendbyte, _pack_len.Length + _ver.Length + _client_cache_len.Length + _client_encrypt_len.Length, info.Length);
                return sendbyte;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public void AnalyzePack(Socket s, byte[] packlen)
        {
            Int32 size = BitConverter.ToInt32(packlen, 0);
            byte[] info = new byte[size];
            byte[] bver = new byte[Protocol.ver_len];
            byte[] bcache = new byte[Protocol.client_cache_len];
            byte[] bencrypt = new byte[Protocol.client_encrypt_len];
            try
            {
                s.Receive(bver, 0, Protocol.ver_len, SocketFlags.None);
                s.Receive(bcache, 0, Protocol.client_cache_len, SocketFlags.None);
                s.Receive(bencrypt, 0, Protocol.client_encrypt_len, SocketFlags.None);
                s.Receive(info, 0, size, SocketFlags.None);
                string ver = Encoding.Default.GetString(bver);
                bool cache = BitConverter.ToBoolean(bcache, 0);
                bool encrypt = BitConverter.ToBoolean(bencrypt, 0);
                Comms.Comms c = new Comms.Comms();
                if (encrypt)
                {
                    info = c.DecryptEx(info, GLLog.Server.Start.EncrypCode);
                }
                if (cache)
                {
                    List<DataEntity.CliErrEntity> ee = c.DeserializeBinary(info);
                    Comms.SvrWriteLog wl = new Comms.SvrWriteLog();
                    if (Server.Start.LogType == Server.Start.StorageType.DB)
                    {
                        wl.WirteCacheLogDB(ee);
                    }
                    else if (Server.Start.LogType == Server.Start.StorageType.File)
                    {
                        wl.WirteCacheLogFile(ee);
                    }
                }
                else
                {
                    string infostr = Encoding.Default.GetString(info);
                    if (infostr.IndexOf("↓") != -1)
                    {
                        string[] isr = infostr.Split('↓');
                        if (isr.Length == 5)
                        {
                            if (DataEntity.SvrData.se.Find(delegate(DataEntity.SvrErrEntity p) { return p.IP == isr[0] && p.Level == isr[1] && p.Logger == isr[2] && p.LogMessage == isr[3] && p.Exception == isr[4]; }) != null)
                            {
                                DataEntity.SvrData.se.Find(delegate(DataEntity.SvrErrEntity p) { return p.IP == isr[0] && p.Level == isr[1] && p.Logger == isr[2] && p.LogMessage == isr[3] && p.Exception == isr[4]; }).Count += 1;
                            }
                            else
                            {
                                DataEntity.SvrData.se.Add(new DataEntity.SvrErrEntity { IP = isr[0], Level = isr[1], Logger = isr[2], LogMessage = isr[3], Exception = isr[4] });
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                info = null;
                bver = null;
                bcache = null;
                bencrypt = null;
            }
        }
    }
}
